<script lang="ts" setup>
import { propTypes } from '@/utils/propTypes'
import { isNumber } from '@/utils/is'
import { ElMessageBox } from 'element-plus'

defineOptions({ name: 'Dialog' })

const slots = useSlots()
// 是否显示弹框
const showModal = ref(false)

const props = defineProps({
  modelValue: propTypes.bool.def(false),
  title: propTypes.string.def('Dialog'),
  width: propTypes.oneOfType([String, Number]).def('50%'),
  scroll: propTypes.bool.def(false), // 是否开启滚动条。如果是的话，按照 maxHeight 设置最大高度
  maxHeight: propTypes.oneOfType([String, Number]).def('400px'),
  closeConfirm: propTypes.bool.def(false)
})

const emit = defineEmits(['update:modelValue'])

const getBindValue = computed(() => {
  const delArr: string[] = ['title', 'maxHeight', 'appendToBody']
  const attrs = useAttrs()
  const obj = { ...attrs, ...props }
  for (const key in obj) {
    if (delArr.indexOf(key) !== -1) {
      delete obj[key]
    }
  }
  return obj
})

const dialogHeight = ref(isNumber(props.maxHeight) ? `${props.maxHeight}px` : props.maxHeight)

const dialogStyle = computed(() => {
  return {
    height: unref(dialogHeight)
  }
})

const showConfirm = async () => {
  if (!props.closeConfirm) return true
  try {
    await ElMessageBox.confirm('确定要关闭吗？', '提示', {
      confirmButtonText: '确定',
      cancelButtonText: '取消',
      type: 'warning'
    })
    return true
  } catch {
    return false
  }
}

/** 是否是关闭拦截 */
const isBeforeClose = ref(false)
// 关闭拦截
const handleBeforeClose = async (done: () => void) => {
  const shouldClose = await showConfirm()
  if (shouldClose) {
    // 设置拦截标志
    isBeforeClose.value = true
    // 放开拦截
    done()
    // 关闭弹窗
    handleShowModal(false)
  }
}
// 点击Icon 关闭
const handleClose = async () => {
  const shouldClose = await showConfirm()
  if (shouldClose) {
    // 设置拦截标志
    isBeforeClose.value = true
    // 关闭弹窗
    handleShowModal(false)
  }
}

// 监听 modelValue 的变化
watch(
  () => props.modelValue,
  async (newVal) => {
    if (newVal) {
      // 打开表格
      handleShowModal(true)
      return
    }
    // 当外部绑定变量设置关闭，并且拦截标志为false,则通过监听拦截
    if (!newVal && !isBeforeClose.value) {
      isBeforeClose.value = true
      // 等待弹框验证
      const shouldClose = await showConfirm()
      // 验证为确定,模态框关闭
      handleShowModal(!shouldClose)
    }
    // 每次状态变化都还原拦截默认值
    isBeforeClose.value = false
  }
)
// 打开弹窗
const handleShowModal = (value: boolean) => {
  // 打开表格
  showModal.value = value
  // 同步外部变量
  emit('update:modelValue', value)
}
</script>

<template>
  <ElDrawer
    v-bind="getBindValue"
    :model-value="showModal"
    :close-on-click-modal="true"
    :size="width"
    destroy-on-close
    lock-scroll
    :show-close="false"
    :before-close="handleBeforeClose"
  >
    <template #header>
      <div class="relative h-54px flex items-center justify-between pl-15px pr-15px">
        <slot name="title">
          <span class="text-lg text-[var(--el-text-color-regular)] font-bold">{{ title }}</span>
        </slot>
        <div
          class="absolute right-15px top-[50%] h-54px flex translate-y-[-50%] items-center justify-between"
        >
          <Icon
            class="is-hover cursor-pointer"
            icon="ep:close"
            hover-color="var(--el-color-primary)"
            color="var(--el-color-info)"
            @click="handleClose"
          />
        </div>
      </div>
    </template>

    <ElScrollbar v-if="scroll" :style="dialogStyle">
      <slot></slot>
    </ElScrollbar>
    <slot v-else></slot>

    <template v-if="slots.footer" #footer>
      <slot name="footer"></slot>
    </template>
  </ElDrawer>
</template>
